package com.wxproject.demo.Realm;
import com.wxproject.demo.Intetcepter.JwtToken;
import com.wxproject.demo.Service.RoleService;
import com.wxproject.demo.Utils.JWTUtil;
import com.wxproject.demo.Utils.RedisUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;
/*
 *项目名: bbstest
 *创建者: ZQF
 *创建时间:2021/3/20 20:32
 *描述: Realm配置
 */

@Component
@Log4j2
public class CustomRealm extends AuthorizingRealm {


    @Autowired
    private RoleService roleService;

    /**
     * 必须重写此方法，不然会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }


    /**
     * 默认使用此方法进行用户名正确与否验证，错误抛出异常即可。
     * doGetAuthenticationInfo方法会执行两次，原因不明，对项目整体无影响。
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
//        System.out.println("————身份认证方法————");
        String token = (String) authenticationToken.getCredentials();
        String refreshToken = (String) authenticationToken.getCredentials();
        // 解密获得username，用于和数据库进行对比
        String username = JWTUtil.getUsername(token);
        String jwtId = JWTUtil.getJwtId(token);
        String userId = JWTUtil.getUserId(refreshToken);
        String lastTime = String.valueOf(RedisUtil.get(userId));
        String newTime = String.valueOf(JWTUtil.getCreateTime(refreshToken));
        //如果token生成日期比缓存中的小，则token为已经被废弃的token，则重新登陆
        if (newTime.compareTo(lastTime)<0){
            throw new AuthenticationException("token已失效，请重新获取token");
        }
        if (username == null || jwtId==null || !JWTUtil.verify(token)) {
            throw new AuthenticationException("token已失效，请重新获取token");
        }
        String password = roleService.getPassword(username);
        if (password == null) {
            throw new AuthenticationException("该用户不存在！");
        }
        int ban = roleService.checkUserBanStatus(username);
            if (ban == 1) {
            throw new AuthenticationException("该用户已被封禁！");
        }
            if (ban==2){
                throw new AuthenticationException("该账户还未被激活");
            }
        if (JWTUtil.verify(token)){
//            System.out.println(redisToken.get("access_token").equals(token)+"  "+"进行了权限认证");
            return new SimpleAuthenticationInfo(token, token, "MyRealm");
        }
        return new SimpleAuthenticationInfo(token, token, "MyRealm");
    }

    /**
     * 只有当需要检测用户权限的时候才会调用此方法，例如checkRole,checkPermission之类的
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//        System.out.println("————权限认证————");
        String username = JWTUtil.getUsername(principals.toString());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //获得该用户角色
        String role = roleService.getRole(username);
        //每个角色拥有默认的权限
        String rolePermission = roleService.getRolePermission(username);
        //每个用户可以设置新的权限
        String permission = roleService.getPermission(username);
        Set<String> roleSet = new HashSet<>();
        Set<String> permissionSet = new HashSet<>();
        //需要将 role, permission 封装到 Set 作为 info.setRoles(), info.setStringPermissions() 的参数
        if (role.equals("admin")){
            roleSet.add("user");
        }
        roleSet.add(role);
        permissionSet.add(rolePermission);
        permissionSet.add(permission);
        //设置该用户拥有的角色和权限
        info.setRoles(roleSet);
        info.setStringPermissions(permissionSet);
        return info;
    }

}